using System;
using System.IO;
using System.Xml;
using System.Drawing;
using System.Net;

namespace UILibrary
{
	/// <summary>
	/// Provides services (for reading only) from RSS files.
	/// </summary>
	public class RssDocument
	{
		public string RssVersion = "";
		public string XmlSource = "";

		public RssChannel[] Item;

		#region [ File and URL handling ]

		/// <summary>
		/// Loads an RSS news source from a URL.
		/// </summary>
		public void LoadFromURL(string url)
		{
			System.Xml.XmlDocument document = new XmlDocument();
			XmlTextReader reader = new XmlTextReader(url);
			reader.Read();
			document.Load(reader);
			reader = null;

			LoadFromXmlDocument(document);
			document = null;
		}


        public void LoadFromString(string content)
        {
            System.Xml.XmlDocument document = new XmlDocument();
            document.LoadXml(content);
            
            LoadFromXmlDocument(document);
            document = null;
        }
		/// <summary>
		/// Loads an RSS news source from a local file.
		/// </summary>
		public void LoadFromFile(string filename)
		{
			System.Xml.XmlDocument document = new XmlDocument();
			document.Load(filename);
			LoadFromXmlDocument(document);
			document = null;
		}

		#endregion

		#region [ Main loading function ]

		/// <summary>
		/// Loads an RSS news source from a given document.
		/// </summary>
		public void LoadFromXmlDocument(XmlDocument document)
		{
			XmlSource = document.OuterXml;

			XmlNode rssNode = document.GetElementsByTagName("rss").Item(0);
			this.RssVersion = rssNode.Attributes["version"].ToString();

			// Get the channel list and check it contains items
			XmlNodeList channelList = document.GetElementsByTagName("channel");
			if (channelList.Count == 0)
				throw new Exception("No RSS channels are defined in this XML document.");

			Item = new RssChannel[channelList.Count];
			int i = 0;
			foreach (XmlNode channelNode in channelList)
			{
				Item[i] = LoadChannelNode(channelNode);
				i++;
			}

		}

		#endregion

		#region [ Xml handlers, load various parts of the file ]

		/// <summary>
		/// Loads an entire rss channel from it's node
		/// </summary>
		private RssChannel LoadChannelNode(XmlNode channelNode)
		{
			RssChannel ret = new RssChannel();
			int itemCount = 0;

			// Loop through the child nodes of the channel. These are either channel "items"m or else
			// they designate a header. Depends on their title.
			// Firstly we process the header nodes, and do the items in a seperate loop.
			foreach (XmlNode childNode in channelNode.ChildNodes)
			{
				switch (childNode.Name)
				{
					case "title":
						ret.Title = childNode.InnerText.ToString();
						break;
					case "link":
						ret.Link = childNode.InnerText.ToString();
						break;
					case "description":
						ret.Description = childNode.InnerText.ToString();
						break;
					case "language":
						ret.Language = childNode.InnerText.ToString();
						break;
					case "copyright":
						ret.Copyright = childNode.InnerText.ToString();
						break;
					case "lastbuilddate":
						ret.LastBuildDateText = childNode.InnerText.ToString();
						break;
					case "docs":
						ret.Docs = childNode.InnerText.ToString();
						break;
					case "image":
						ret.RssImage = LoadImageNode(childNode);
						break;

					case "item":
						itemCount++;
						break;
				}
			}

			// Now we can loop through the news items, and create those.
			ret.Item = new RssNewsItem[itemCount];
			int i = 0;
			foreach (XmlNode childNode in channelNode.ChildNodes)
			{
				if (childNode.Name=="item")
				{
					ret.Item[i] = LoadItemNode(childNode);
					i++;
				}
			}

			// Return the channel
			return ret;

		}

		private RssNewsItem LoadItemNode(XmlNode itemNode)
		{
			RssNewsItem ret = new RssNewsItem();

			foreach (XmlNode fieldNode in itemNode.ChildNodes)
			{
				switch (fieldNode.Name)
				{
					case "title":
						ret.Title = fieldNode.InnerText;
						break;
					case "link":
						ret.Link = fieldNode.InnerText;
						break;
					case "description":
						ret.Description = fieldNode.InnerText;
                        break;    
                    case "category":
                        ret.Category = fieldNode.InnerText;
						break;
				}
			}

			// Actually return the item
			return ret;
		}

		private RssImage LoadImageNode(XmlNode imageNode)
		{
			RssImage ret = new RssImage();

			foreach (XmlNode fieldNode in imageNode.ChildNodes)
			{
				switch (fieldNode.Name)
				{
					case "title":
						ret.Title = fieldNode.InnerText;
						break;
					case "link":
						ret.Link = fieldNode.InnerText;
						break;
					case "url":
						ret.URL = fieldNode.InnerText;
						break;
				}
			}

			// Actually return the item
			return ret;
		}

		#endregion
	}

	#region [ Structures ]

	public struct RssChannel
	{
		public string Title;
		public string Link;
		public string Description;
		public string Language;
		public string LastBuildDateText;
		public string Copyright;
		public string Docs;
		public RssImage RssImage;

		public RssNewsItem[] Item;

		public override string ToString()
		{
			return this.Title;
		}
	}

	public struct RssNewsItem
	{
		public string Title;
		public string Description;
		public string Link;
        public string Category;

		public override string ToString()
		{
			return this.Title;
		}

	}

	public struct RssImage
	{
		public string Title;
		public string URL;
		public string Link;

		public override string ToString()
		{
			return this.Title;
		}

		public System.Drawing.Image ToImage()
		{

			System.Net.WebClient client = new WebClient();
			Stream data = client.OpenRead(URL);
			System.Drawing.Image ret = System.Drawing.Image.FromStream(data);
			data.Close();
			data = null;
			client.Dispose();
			client = null;
			return ret;
		}
	}

	#endregion
}
